package chain

import "strconv"

// HandlerInterface 职责的接口，也就是处理请求的接口
type HandlerInterface interface {
	// SomeCondition 根据某些条件来判断是否属于自己处理的职责范围
	// 判断条件比如，从外部传入的参数，或者这里主动去获取的外部数据
	// 如从数据库中获取等，这是个示意
	SomeCondition(in int) bool
	// HandleRequest 示意处理请求的方法，虽然这个示意方法是没有传入参数的
	// 但实际是可以传入参数的，根据具体需要来选择是否传递参数
	HandleRequest(in int, str string) string
}

type Handler struct {
	//嵌入了其他类型的结构体类型本身是一个代理，在调用其实例所代理的方法时，Go 会首先查看结构体自身是否实现了该方法。
	//如果实现了，Go 就会优先使用结构体自己实现的方法。
	//如果没有实现，那么 Go 就会查找结构体中的嵌入字段的方法集合中，是否包含了这个方法。
	//如果多个嵌入字段的方法集合中都包含这个方法，那么我们就说方法集合存在交集。这个时候，Go 编译器就会因无法确定究竟使用哪个方法而报错。
	HandlerInterface
	successor *Handler
}

func (h *Handler) SetSuccessor(successor *Handler) {
	h.successor = successor
}

func (h *Handler) HandleRequest(in int, str string) string {
	if h.HandlerInterface.SomeCondition(in) {
		// 如果属于自己处理的职责范围，就在这里处理请求
		// 具体的处理代码
		return h.HandlerInterface.HandleRequest(in, str)
	}
	// 如果不属于自己处理的职责范围，那就判断是否还有后继的职责对象
	// 如果有，就转发请求给后继的职责对象
	// 如果没有，什么都不做，自然结束
	if h.successor != nil {
		return h.successor.HandleRequest(in, str)
	}
	if h.SomeCondition(in) {
		return strconv.Itoa(in) + " default condition handler"
	}
	return strconv.Itoa(in) + " last handler"
}

func (h *Handler) SomeCondition(in int) bool {
	return in < 1000
}

type ConcreteHandler1 struct {
}

func (c *ConcreteHandler1) SomeCondition(in int) bool {
	return in < 100
}

func (c *ConcreteHandler1) HandleRequest(in int, str string) string {
	//if str == "handler1" {
	//	return strconv.Itoa(in) + " handler 1"
	//}
	//return "not handler 1"
	return strconv.Itoa(in) + " handler 1 " + str
}

func NewConcreteHandler1() *Handler {
	return &Handler{
		HandlerInterface: &ConcreteHandler1{},
	}
}

type ConcreteHandler2 struct {
}

func (c *ConcreteHandler2) SomeCondition(in int) bool {
	return in < 200
}

func (c *ConcreteHandler2) HandleRequest(in int, str string) string {
	return strconv.Itoa(in) + " handler 2 " + str
}

func NewConcreteHandler2() *Handler {
	return &Handler{
		HandlerInterface: &ConcreteHandler2{},
	}
}

type ConcreteHandler3 struct {
}

func (c *ConcreteHandler3) SomeCondition(in int) bool {
	return in < 300
}

func (c *ConcreteHandler3) HandleRequest(in int, str string) string {
	return strconv.Itoa(in) + " handler 3 " + str
}

func NewConcreteHandler3() *Handler {
	return &Handler{
		HandlerInterface: &ConcreteHandler3{},
	}
}
